package kernel

import (
	"awesomeTask/system/helper"
	"reflect"
	"sync"
)

var iocInstance IocInstance
var once sync.Once
var instanceRegister sync.Map //此处绑定实例化对象的方式
var objMap sync.Map           //此处绑定实例化的对象

type Ioc interface {
	RegisterObject(name string, obj interface{})                                    //注册对象通过名称
	GetObjectByName(name string)                                                    //获取对象
	RemoveObjectByName(name string)                                                 //移除对象通过名称
	GetObjectMethod(obj interface{})                                                //获取某个对象全部可执行的方法
	CallFunByName(obj interface{}, fun string, params ...interface{})               //动态执行函数
	BindCreateObject(name string, instanceFun func() interface{}, isSingleTon bool) //绑定某个对象实例化的方法
	GetInstanceOrCreate(name string) interface{}                                    //获取某个实例不存在则创建
}
type IocInstance struct {
	//已经注入的对象
}

func (ioc *IocInstance) RegisterObject(name string, obj interface{}) {
	objMap.Store(name, obj)
}
func (ioc *IocInstance) GetObjectByName(name string) interface{} {
	if obj, ok := objMap.Load(name); ok {
		return obj
	}
	return nil
}
func (ioc *IocInstance) RemoveObjectByName(name string) {
	if _, ok := objMap.Load(name); ok {
		objMap.Delete(name)
	}
}
func (ioc *IocInstance) CallFunByName(obj interface{}, fun string, params ...interface{}) interface{} {
	defer func() {
		if r := recover(); r != nil {
			obj := ioc.GetObjectByName("logger")
			switch r.(type) {
			case error:
				ioc.CallFunByName(obj, "Error", "funName:"+fun+" info:"+helper.PrintStackTrace(r.(error)))
			case string:
				ioc.CallFunByName(obj, "Error", "funName:"+fun+" info:"+r.(string))
				break
			}

		}
	}()
	inputs := make([]reflect.Value, len(params))
	for k, pamra := range params {
		inputs[k] = reflect.ValueOf(pamra)
	}
	result := reflect.ValueOf(obj).MethodByName(fun).Call(inputs)
	return result
}
func (ioc *IocInstance) BindCreateObject(name string, instanceFun func() interface{}, isSingleTon bool) {
	var instanceInfo = make(map[string]interface{})
	instanceInfo["fun"] = instanceFun()
	instanceInfo["isSingleTon"] = isSingleTon
	instanceRegister.Store(name, instanceInfo)
}
func GetIocInstance() IocInstance {
	once.Do(func() {
		iocInstance = IocInstance{}
	})
	return iocInstance
}
func (ioc *IocInstance) MethodExist(obj interface{}, fun string) bool {
	return reflect.ValueOf(obj).MethodByName(fun).IsValid()
}
func (ioc *IocInstance) GetInstanceOrCreate(name string) interface{} {
	if obj, ok := objMap.Load(name); ok {
		return obj
	}
	instanceInfo, ok := instanceRegister.Load(name)
	if !ok {
		panic("Ioc failed find the instance of " + name + "")
		return nil
	}
	obj := instanceInfo.(map[string]interface{})["fun"]
	if instanceInfo.(map[string]interface{})["isSingleTon"].(bool) {
		objMap.Store(name, obj)
	}
	return obj
}
